package p2pcdnsim.cdn;

import p2pcdnsim.exception.PortAlreadyInUseException;
import p2pcdnsim.network.ApplicationProcess;
import p2pcdnsim.network.DatagramPacket;
import p2pcdnsim.network.DatagramSocket;
import desmoj.core.simulator.SimTime;


public class VoDOriginServer extends OriginServer {

	public VoDOriginServer(CDN cdn, String name) {
		super(cdn.getModel(), name, cdn);
	}

	@Override
	protected void run() {
		DatagramSocket socket = null;
		try {
			socket = this.createDatagramSocket(80);
		} catch (PortAlreadyInUseException e) {
			throw new RuntimeException(e);
		}
		
		while(true) {
			//System.out.println("["+this.currentTime()+"] OriginServer: Waiting for a datagram...");
			DatagramPacket packet = socket.receive();
			SubRoutine routine =  new SubRoutine(this, packet);
			routine.activate(new SimTime(0.0));	
		}
	}

	
	
	private class SubRoutine extends ApplicationProcess {

		DatagramPacket packet;
		VoDOriginServer parent;
		
		public SubRoutine(VoDOriginServer parent, DatagramPacket packet) {
			super(parent.getModel(), parent.getName());
			this.parent = parent;
			this.packet = packet;
			this.setApplicationLayer(parent.getApplicationLayer());
		}
		
		@Override
		protected void run() {
			DatagramSocket routineSocket = createDatagramSocket();
			//System.out.println("["+this.currentTime()+"] OriginServer subroutine: received request");
			ObjectRequest request = (ObjectRequest)packet.getMessage();
			//System.out.println("["+this.currentTime()+"] OriginServer subroutine: requesting object "+request.getObjectId());
			VideoContent video = (VideoContent)contents.get(request.getObjectId());
			//System.out.println("["+this.currentTime()+"] OriginServer subroutine: preparing to send "+video);
			
			if(video == null) 
				throw new RuntimeException("Origin Server does not contain requested object: [id="+request.getObjectId()+"]");
			// The line bellow was put to test the simulator while the inconsistencies on xml is not solved
			//if(video == null) 
			//	video = new VideoContent(request.getObjectId(),100,300000);
			
			//Fragmenting...
			long lenRemaining = video.getLength();
			int packetSize = 1400;
			while(lenRemaining>0) {
				VideoContent videoFragment;
				if(lenRemaining > packetSize) {
					videoFragment = new VideoContent(video.getObjectId(),packetSize,video.getBitRate());
					lenRemaining-=packetSize;
				} else {
					videoFragment = new VideoContent(video.getObjectId(),lenRemaining,video.getBitRate());
					videoFragment.setLastFragment(true);
					lenRemaining=0;
				}
				videoFragment.setFragment(true);
				videoFragment.setTotalSize(video.getLength());
				DatagramPacket newpacket = new DatagramPacket(routineSocket.getAddress(),routineSocket.getPort(),packet.getSourceAddress(),packet.getSourcedPort());
				newpacket.setMessage(videoFragment);
				routineSocket.send(newpacket);
				SimTime time = new SimTime(1/(((double)video.getBitRate())/(packetSize*8)));
				
				if(this.isScheduled()) throw new RuntimeException("trying to hold but already scheduled at "+this.scheduledAt());
				hold(time);
			}
			routineSocket.close();
		}
	}

}
